using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace mouseAsteriodz
{
    public class Asteriod
    {
        public Texture2D image;
        public Vector2 position;
        public Vector2 velocity;
        public Vector2 centerOfImage;
        public Asteriod(ContentManager content, string imageFileName)
        {
            image = content.Load<Texture2D>(imageFileName);
            centerOfImage = new Vector2(image.Width / 2, image.Height / 2);
        }
        public void setUpPositionAndVelocity(Vector2 startPosition, Vector2 startVelocity)
        {
            position = startPosition;
            velocity = startVelocity;
        }

        internal void Update()
        {
            position += velocity;
        }
    }
    public class Cursor
    {
        public Texture2D image;
        public Vector2 centerOfImage;
        public Vector2 position;
        public float rotation;
        private const float turnspeed = 0.3f;
        float newrotation = 0.0f;
        public Cursor(ContentManager content, string imageFileName, Vector2 startPosition)
        {
            image = content.Load<Texture2D>(imageFileName);
            position = startPosition;
            centerOfImage = new Vector2(image.Width / 2, image.Height / 2);
        }


        internal void Update(MouseState mouseState, MouseState previousMouseState)
        {
            position = new Vector2(mouseState.X, mouseState.Y);
            
            if (mouseState.X != previousMouseState.X && mouseState.Y != previousMouseState.Y)
                newrotation = (float)Math.Atan2(previousMouseState.Y - mouseState.Y, previousMouseState.X - mouseState.X) - MathHelper.PiOver2;
            rotation = MathHelper.Lerp(rotation, newrotation, turnspeed);
        }
    }
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        List<Asteriod> asteriodz;
        Cursor cursor;
        Vector2 centerOfScreen = Vector2.Zero;
        const int SCREENWIDTH = 800;
        const int SCREENHEIGHT = 800;
        const int NUMOFASTERIODS = 4;
        const string CURSORPATH = "ship";
        const string ASTERIODPATH = "asteriod";
        MouseState mouseState = Mouse.GetState();
        MouseState previousMouseState = Mouse.GetState();
        private Random r = new Random();
        private const float MINASTERIODSPEED = 3.0f;
        private const float MAXASTERIODSPEED = 5.0f;
        private int millisecondsBetweenNewAsteriod = 750;
        private int millisecondsSinceNewAsteriod = 0;
        private const int MINIMUMTIMEBETWEENASTERIODS = 100;
        private const int TIMEDECREASESPEED = 25;
        private bool GAMEOVERLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOL = false;
        SpriteFont font;
        int score = 0;
        private Vector2 scoreStringPostition = new Vector2(50,50);
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferWidth = SCREENWIDTH;
            graphics.PreferredBackBufferHeight = SCREENHEIGHT;
            //IsMouseVisible = true;
            graphics.ApplyChanges();
            centerOfScreen = new Vector2(SCREENWIDTH, SCREENHEIGHT);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            asteriodz = new List<Asteriod>();
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            cursor = new Cursor(Content, CURSORPATH, centerOfScreen);
            font = Content.Load<SpriteFont>("Font");
            asteriodz = new List<Asteriod>();
            Mouse.SetPosition(graphics.PreferredBackBufferWidth / 2, graphics.PreferredBackBufferHeight / 2);
            score = 0;
        }

        private void createNewAsteriod()
        {
            asteriodz.Add(setUpAsteriod());
        }

        private Asteriod setUpAsteriod()
        {
            Asteriod newAsteriod = new Asteriod(Content, ASTERIODPATH);
            //top=1 right=2 bottom=3 left=4
            int side = r.Next(1, 5);
            Vector2 newStartPosition = findNewStartPosition(side, newAsteriod);
            Vector2 newStartVelocity = findNewStartVelocity(newStartPosition, newAsteriod, side);
            newAsteriod.setUpPositionAndVelocity(newStartPosition, newStartVelocity);
            return newAsteriod;
        }

        private Vector2 findNewStartVelocity(Vector2 newStartPosition, Asteriod newAsteriod, int sideNum)
        {
            Vector2 newVelocity = Vector2.Zero;
            Vector2 targetPosition = Vector2.Zero;
            switch (sideNum) //finds a position on opposite side
            {
                case 3: //bottom -> top
                    targetPosition.X = MathHelper.Lerp(-newAsteriod.image.Width, graphics.PreferredBackBufferWidth, (float)r.NextDouble());
                    targetPosition.Y = -newAsteriod.image.Height;
                    break;
                case 4: //right -> left
                    targetPosition.X = -newAsteriod.image.Width;
                    targetPosition.Y = MathHelper.Lerp(-newAsteriod.image.Height, graphics.PreferredBackBufferHeight, (float)r.NextDouble());
                    break;
                case 1: //top -> bottom
                    targetPosition.X = MathHelper.Lerp(-newAsteriod.image.Width, graphics.PreferredBackBufferWidth, (float)r.NextDouble());
                    targetPosition.Y = graphics.PreferredBackBufferHeight;
                    break;
                case 2: //left -> right
                    targetPosition.X = graphics.PreferredBackBufferWidth;
                    targetPosition.Y = MathHelper.Lerp(-newAsteriod.image.Height, graphics.PreferredBackBufferHeight, (float)r.NextDouble());
                    break;
            }
            newVelocity = targetPosition - newStartPosition;
            newVelocity.Normalize();
            newVelocity *= MathHelper.Lerp(MINASTERIODSPEED, MAXASTERIODSPEED, (float)r.NextDouble());
            return newVelocity;
        }

        Vector2 findNewStartPosition(int sideNum, Asteriod newAsteriod)
        {
            Vector2 newPosition = Vector2.Zero;
            switch (sideNum) //finds a position on random side
            {
                case 1: //top
                    newPosition.X = MathHelper.Lerp(-newAsteriod.image.Width, graphics.PreferredBackBufferWidth, (float)r.NextDouble());
                    newPosition.Y = -newAsteriod.image.Height;
                    break;
                case 2: //left
                    newPosition.X = -newAsteriod.image.Width;
                    newPosition.Y = MathHelper.Lerp(-newAsteriod.image.Height, graphics.PreferredBackBufferHeight, (float)r.NextDouble());
                    break;
                case 3: //bottom 
                    newPosition.X = MathHelper.Lerp(-newAsteriod.image.Width, graphics.PreferredBackBufferWidth, (float)r.NextDouble());
                    newPosition.Y = graphics.PreferredBackBufferHeight;
                    break;
                case 4: //right
                    newPosition.X = graphics.PreferredBackBufferWidth;
                    newPosition.Y = MathHelper.Lerp(-newAsteriod.image.Height, graphics.PreferredBackBufferHeight, (float)r.NextDouble());
                    break;
            }
            return newPosition;
        }


        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            if (!GAMEOVERLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOL)
            {
                millisecondsSinceNewAsteriod += gameTime.ElapsedGameTime.Milliseconds;
                if (millisecondsSinceNewAsteriod > millisecondsBetweenNewAsteriod)
                {
                    createNewAsteriod();
                    millisecondsSinceNewAsteriod = 0;
                    if (millisecondsBetweenNewAsteriod > MINIMUMTIMEBETWEENASTERIODS)
                        millisecondsBetweenNewAsteriod -= TIMEDECREASESPEED;
                }
                updateAsteriods();
                updateCursor();
                score += 10;
            }
            else if (Keyboard.GetState().IsKeyDown(Keys.Space))
                resetGame();

            base.Update(gameTime);
        }

        private void resetGame()
        {
            millisecondsBetweenNewAsteriod = 750;
            GAMEOVERLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOL = false;
            LoadContent();
        }

        private void updateAsteriods()
        {
            Rectangle cursorHitbox = new Rectangle((int)cursor.position.X, (int)cursor.position.Y, cursor.image.Width, cursor.image.Height);
            foreach (Asteriod ast in asteriodz)
            {
                ast.Update();
                float distance = Vector2.Distance(ast.position + ast.centerOfImage, cursor.position + cursor.centerOfImage);
                if(distance < 35)
                    GAMEOVERLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOL = true;
            }
        }

        private void updateCursor()
        {
            cursor.Update(mouseState, previousMouseState);
            previousMouseState = mouseState;
            mouseState = Mouse.GetState();
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);
            if (!GAMEOVERLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOL)
            {
                spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.Additive);
                spriteBatch.DrawString(font, "Score: " + score.ToString(), scoreStringPostition, Color.WhiteSmoke);
                spriteBatch.Draw(cursor.image, cursor.position, null, Color.White, cursor.rotation, cursor.centerOfImage, 1.0f, SpriteEffects.None, 0);
                foreach (Asteriod asteriod in asteriodz)
                    spriteBatch.Draw(asteriod.image, asteriod.position, Color.White);
                spriteBatch.End();
            }
            else
            {
                spriteBatch.Begin();
                string gameOversString = "          Game Over!\nPress Space to Restart\n          Score:" + score.ToString();
                spriteBatch.DrawString(font, gameOversString, new Vector2(graphics.PreferredBackBufferWidth / 2, graphics.PreferredBackBufferHeight / 2) - (font.MeasureString(gameOversString) / 2), Color.WhiteSmoke);
                spriteBatch.End();
            }
            base.Draw(gameTime);
        }
    }
}
